#ifndef V2_NIM_SIGNALLING_SERVICE_H
#define V2_NIM_SIGNALLING_SERVICE_H

#include "v2_nim_internal.hpp"

namespace v2 {

/// @brief 信令服务
/// @pre
/// 调用 `V2NIMClient::get()` 拿到 client 实例
/// 调用 `client.getSignallingService()` 拿到 signallingService 实例
/// @par 示例代码
/// @code
/// auto& client = V2NIMClient::get();
/// auto& signallingService = client.getSignallingService();
/// @endcode
class V2NIMSignallingService {
public:
    /// 直接呼叫对方加入房间
    /// 信令正常流程为
    ///  - 创建房间（createRoom），房间创建默认有效时间 2 个小时，
    ///  - 自己加入房间（join）
    ///  - 邀请对方加入房间（invite）
    /// 上述的房间是信令的房间，不是音视频的房间，因此需要三次向服务器交互才能建立相关流程
    /// call 接口同时由服务器实现了上述三个接口的功能，可以加速呼叫流程，如果你需要精确控制每一步，则需要调用上述每一个接口
    /// @param params 呼叫参数
    /// @param success 成功回调
    /// @param failure 失败回调
    /// @return void
    /// @par 示例代码
    /// @code
    /// V2NIMSignallingCallParams callParameter;
    /// callParameter.calleeAccountId = "calleeAccountId";
    /// callParameter.requestId = "request UUID";
    /// callParameter.channelType = V2NIM_SIGNALLING_CHANNEL_TYPE_AUDIO;
    /// signallingService.call(
    ///     callParameter,
    ///     [](const V2NIMSignallingCallResult& result) {
    ///         // call success
    ///     },
    ///     [](V2NIMError error) {
    ///         // call failed, handle error
    ///     });
    /// @endcode
    virtual void call(const V2NIMSignallingCallParams& params,
        const V2NIMSuccessCallback<const V2NIMSignallingCallResult&>& success,
        const V2NIMFailureCallback& failure) = 0;

    /// 呼叫建立，包括加入信令频道房间，同时接受对方呼叫
    ///  - 组合接口（join+accept）
    ///  - 如果需要详细处理每一步骤，则可以单独调用 join 接口，之后再调用 accept 接口
    /// @param params 建立呼叫参数
    /// @param success 成功回调
    /// @param failure 失败回调
    /// @return void
    /// @par 示例代码
    /// @code
    /// V2NIMSignallingCallSetupParams callSetupParams;
    /// callSetupParams.channelId = "channelId";
    /// callSetupParams.callerAccountId = "callerAccountId";
    /// callSetupParams.requestId = "request UUID";
    /// signallingService.callSetup(
    ///     callSetupParams,
    ///     [](const V2NIMSignallingCallSetupResult& result) {
    ///         // call setup success
    ///     },
    ///     [](V2NIMError error) {
    ///         // call setup failed, handle error
    ///     });
    /// @endcode
    virtual void callSetup(const V2NIMSignallingCallSetupParams& params,
        const V2NIMSuccessCallback<V2NIMSignallingCallSetupResult>& success,
        const V2NIMFailureCallback& failure) = 0;

    /// 创建信令房间
    /// 频道与房间一一对应，可以理解为同一概念，相同的频道名，在服务器同时只能存在一个
    /// 房间创建默认有效时间 2 个小时，房间人数默认上限 100 人
    /// @param channelType 频道类型
    /// @param channelName 频道名称， 建议使用与业务有相关场景的名称，便于页面显示
    /// @param channelExtension 频道相关扩展字段，长度限制 4096，与频道绑定，JSON 格式
    /// @param success 成功回调
    /// @param failure 失败回调
    /// @return void
    /// @par 示例代码
    /// @code
    /// signallingService.createRoom(
    ///     V2NIM_SIGNALLING_CHANNEL_TYPE_AUDIO,
    ///     "channelName",
    ///     "{\"key\":\"value\"}",
    ///     [](const V2NIMSignallingChannelInfo& result) {
    ///         // create room success
    ///     },
    ///     [](V2NIMError error) {
    ///         // create room failed, handle error
    ///     });
    /// @endcode
    virtual void createRoom(V2NIMSignallingChannelType channelType,
        const nstd::optional<nstd::string>& channelName,
        const nstd::optional<nstd::string>& channelExtension,
        const V2NIMSuccessCallback<const V2NIMSignallingChannelInfo&>& success,
        const V2NIMFailureCallback& failure) = 0;

    /// 关闭信令房间接口
    /// 该接口调用后会触发关闭通知给房间内所有人，房间内的所有人均可以调用该接口
    /// 信令房间如果没有主动调用接口关闭，会等待 2 个小时，2 个小时没有新的用户加入，则服务器自行销毁对应的信令房间
    /// @param channelId 频道 ID
    /// @param offlineEnabled 是否支持离线推送，如果支持离线推送，用户离线后，仍然可以收到信令通知
    /// @param serverExtension 服务器扩展字段，长度限制 4096，JSON 格式
    /// @param success 成功回调
    /// @param failure 失败回调
    /// @return void
    /// @par 示例代码
    /// @code
    /// signallingService.closeRoom(
    ///     "channelId",
    ///     true,
    ///     "{\"key\":\"value\"}",
    ///     []() {
    ///         // close room success
    ///     },
    ///     [](V2NIMError error) {
    ///         // close room failed, handle error
    ///     });
    /// @endcode
    virtual void closeRoom(const nstd::string& channelId,
        const nstd::optional<bool>& offlineEnabled,
        const nstd::optional<nstd::string>& serverExtension,
        const V2NIMSuccessCallback<void>& success,
        const V2NIMFailureCallback& failure) = 0;

    /// 加入信令房间接口
    /// 该接口调用后会触发加入通知给房间内所有人，默认有效期为 5 分钟
    /// @param params 加入房间参数
    /// @param success 成功回调
    /// @param failure 失败回调
    /// @return void
    /// @par 示例代码
    /// @code
    /// V2NIMSignallingJoinParams joinParameter;
    /// joinParams.channelId = "channelId";
    /// signallingService.joinRoom(
    ///     joinParameter,
    ///     [](const V2NIMSignallingChannelInfo& result) {
    ///         // join room success
    ///     },
    ///     [](V2NIMError error) {
    ///         // join room failed, handle error
    ///     });
    /// @endcode
    virtual void joinRoom(const V2NIMSignallingJoinParams& params,
        const V2NIMSuccessCallback<const V2NIMSignallingRoomInfo&>& success,
        const V2NIMFailureCallback& failure) = 0;

    /// 离开信令房间接口
    /// 该接口调用后会触发离开通知给房间内所有人
    /// @param channelId 频道 ID
    /// @param offlineEnabled 是否支持离线推送，如果支持离线推送，用户离线后，仍然可以收到信令通知
    /// @param serverExtension 服务器扩展字段，长度限制 4096，JSON 格式
    /// @param success 成功回调
    /// @param failure 失败回调
    /// @return void
    /// @par 示例代码
    /// @code
    /// signallingService.leaveRoom(
    ///     "channelId",
    ///     true,
    ///     "{\"key\":\"value\"}",
    ///     []() {
    ///         // leave room success
    ///     },
    ///     [](V2NIMError error) {
    ///         // leave room failed, handle error
    ///     });
    /// @endcode
    virtual void leaveRoom(const nstd::string& channelId,
        const nstd::optional<bool>& offlineEnabled,
        const nstd::optional<nstd::string>& serverExtension,
        const V2NIMSuccessCallback<void>& success,
        const V2NIMFailureCallback& failure) = 0;

    /// @brief 邀请成员加入信令房间接口，房间内的人均可以发送邀请
    /// 该接口调用后会触发邀请通知给对方， 发送方可以配置是否需要发送推送，默认情况下不推送
    /// @param params 邀请参数
    /// @param success 成功回调
    /// @param failure 失败回调
    /// @return void
    /// @par 示例代码
    /// @code
    /// V2NIMSignallingInviteParams inviteParameter;
    /// inviteParameter.channelId = "channelId";
    /// inviteParameter.accountId = "accountId";
    /// inviteParameter.requestId = "request UUID";
    /// signallingService.invite(
    ///     inviteParameter,
    ///     []() {
    ///         // invite success
    ///     },
    ///     [](V2NIMError error) {
    ///         // invite failed, handle error
    ///     });
    /// @endcode
    virtual void invite(const V2NIMSignallingInviteParams& params,
        const V2NIMSuccessCallback<void>& success,
        const V2NIMFailureCallback& failure) = 0;

    /// @brief 取消之前的邀请成员加入信令房间接口
    ///  - 该接口调用后会触发取消邀请通知给对方
    ///  - 只能取消自己的邀请请求
    /// @param params 取消邀请参数
    /// @param success 成功回调
    /// @param failure 失败回调
    /// @return void
    /// @par 示例代码
    /// @code
    /// V2NIMSignallingCancelInviteParams cancelInviteParameter;
    /// cancelInviteParameter.channelId = "channelId";
    /// cancelInviteParameter.accountId = "accountId";
    /// cancelInviteParameter.requestId = "request UUID";
    /// signallingService.cancelInvite(
    ///     cancelInviteParameter,
    ///     []() {
    ///         // cancel invite success
    ///     },
    ///     [](V2NIMError error) {
    ///         // cancel invite failed, handle error
    ///     });
    /// @endcode
    virtual void cancelInvite(const V2NIMSignallingCancelInviteParams& params,
        const V2NIMSuccessCallback<void>& success,
        const V2NIMFailureCallback& failure) = 0;

    /// @brief 拒绝别人的邀请加入信令房间请求，该接口调用后会触发拒绝邀请通知给对方
    /// @param params 拒绝邀请参数
    /// @param success 成功回调
    /// @param failure 失败回调
    /// @return void
    /// @par 示例代码
    /// @code
    /// V2NIMSignallingRejectInviteParams rejectInviteParameter;
    /// rejectInviteParameter.channelId = "channelId";
    /// rejectInviteParameter.accountId = "accountId";
    /// rejectInviteParameter.requestId = "request UUID";
    /// signallingService.rejectInvite(
    ///     rejectInviteParameter,
    ///     []() {
    ///         // reject invite success
    ///     },
    ///     [](V2NIMError error) {
    ///         // reject invite failed, handle error
    ///     });
    /// @endcode
    virtual void rejectInvite(const V2NIMSignallingRejectInviteParams& params,
        const V2NIMSuccessCallback<void>& success,
        const V2NIMFailureCallback& failure) = 0;

    /// @brief 接受别人的邀请加入信令房间请求，该接口调用后会触发接受邀请通知给对方
    /// @param params 接受邀请参数
    /// @param success 成功回调
    /// @param failure 失败回调
    /// @return void
    /// @par 示例代码
    /// @code
    /// V2NIMSignallingAcceptInviteParams acceptInviteParameter;
    /// acceptInviteParameter.channelId = "channelId";
    /// acceptInviteParameter.accountId = "accountId";
    /// acceptInviteParameter.requestId = "request UUID";
    /// signallingService.acceptInvite(
    ///     acceptInviteParameter,
    ///     []() {
    ///         // accept invite success
    ///     },
    ///     [](V2NIMError error) {
    ///         // accept invite failed, handle error
    ///     });
    /// @endcode
    virtual void acceptInvite(const V2NIMSignallingAcceptInviteParams& params,
        const V2NIMSuccessCallback<void>& success,
        const V2NIMFailureCallback& failure) = 0;

    /// @brief 发送自定义控制指令，可以实现自定义相关的业务逻辑
    /// 可以发送给指定用户，如果不指定，则发送给信令房间内的所有人
    /// 该接口不做成员校验，允许非频道房间内的成员调用，但是接受者必须在频道房间内或者是创建者
    /// 接口调用后会发送一个控制通知
    ///  - 如果指定了接受者： 则通知发送给接受者
    ///  - 如果未指定接受者：则发送给房间内的所有人
    ///  - 通知仅发在线
    /// @param channelId 频道 ID
    /// @param receiverAccountId 接受者账号 ID，如果不指定，则发送给房间内的所有人
    /// @param serverExtension 服务器扩展字段，长度限制 4096，JSON 格式
    /// @param success 成功回调
    /// @param failure 失败回调
    /// @return void
    /// @par 示例代码
    /// @code
    /// signallingService.sendControl(
    ///     "channelId",
    ///     "receiverAccountId",
    ///     "{\"key\":\"value\"}",
    ///     []() {
    ///         // send control success
    ///     },
    ///     [](V2NIMError error) {
    ///         // send control failed, handle error
    ///     });
    /// @endcode
    virtual void sendControl(const nstd::string& channelId,
        const nstd::optional<nstd::string>& receiverAccountId,
        const nstd::optional<nstd::string>& serverExtension,
        const V2NIMSuccessCallback<void>& success,
        const V2NIMFailureCallback& failure) = 0;

    /// @brief 根据频道名称查询频道房间信息
    /// @param channelName 频道名称
    /// @param success 成功回调
    /// @param failure 失败回调
    /// @return void
    /// @par 示例代码
    /// @code
    /// signallingService.getRoomInfoByChannelName(
    ///     "channelName",
    ///     [](const V2NIMSignallingRoomInfo& result) {
    ///         // get room info success
    ///     },
    ///     [](V2NIMError error) {
    ///         // get room info failed, handle error
    ///     });
    /// @endcode
    virtual void getRoomInfoByChannelName(const nstd::string& channelName,
        const V2NIMSuccessCallback<const V2NIMSignallingRoomInfo&>& success,
        const V2NIMFailureCallback& failure) = 0;

    /// @brief 添加信令监听器
    /// @param listener 信令监听器
    /// @return void
    /// @par 示例代码
    /// @code
    /// signallingService.addSignallingListener(listener);
    /// @endcode
    virtual void addSignallingListener(const V2NIMSignallingListener& listener) = 0;

    /// @brief 移除信令监听器
    /// @param listener 信令监听器
    /// @return void
    /// @par 示例代码
    /// @code
    /// signallingService.removeSignallingListener(listener);
    /// @endcode
    virtual void removeSignallingListener(const V2NIMSignallingListener& listener) = 0;
};

}  // namespace v2

#endif  // V2_NIM_SIGNALLING_SERVICE_H
